home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
AmigActive 10
/
AACD 10.iso
/
AACD
/
Magazine
/
Online
/
httpproxy
/
src
/
cache.c
next >
Wrap
C/C++ Source or Header
|
1996-08-20
|
28KB
|
994 lines
/*(( "Header" */
/*
* $Id: cache.c,v 1.6 1996/08/20 17:36:43 mshopf Exp mshopf $
*
* (c) 1995-96 Matthias Hopf
*
* Cache file maintainance for HttpProxy.
*
*/
/*
* $Log: cache.c,v $
* Revision 1.6 1996/08/20 17:36:43 mshopf
* *very* small bug fix...
*
* Revision 1.5 1996/08/12 03:33:36 mshopf
* on delete checking for related file (return 7).
*
* Revision 1.4 1996/08/11 22:25:15 mshopf
* reworked debug messages.
*
* Revision 1.3 1996/07/30 13:57:03 mshopf
* bug fixes.
* better escaping scheme.
* deleteing all files in @temp and @trash on startup now.
* removing empty cache files automatically.
*
* Revision 1.2 1996/07/19 19:59:55 mshopf
* hash function bugfix.
*
* Revision 1.1 1996/07/17 16:42:42 mshopf
* Initial revision
*
*/
/*)) */
/*(("Includes/Constants" */
#include <ctype.h>
#include <string.h>
#include <exec/exec.h>
#include <dos.h>
#include <dos/exall.h>
#include <dos/datetime.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include "httpproxy.h"
#include "logging.h"
#include "cache.h"
/*)) */
/*(( "Globals" */
/* Escape character tables */
/* Entries specify the escaping character / the escaped character,
* '\0' for valid characters / not escaped chars */
static char InvalidChars [256]; /* initialized with '\0' */
static char EscapedChars [256]; /* '' */
/*)) */
/*(( "EscapePartial ()" */
/* private: Escape special chars in file/dir part.
* returns: 0: not possible, 1: final filname part reached 3: intermediate dir part */
/* Url and Dir pointers are updated accordingly (only on return value != 0). */
/* The first two parts may have special treatment (protocol and host) */
static int EscapePartial (const char **UrlPtr, char **DirPtr, int PartNumber)
{
int len = MAX_FILE_LEN - 3;
const char *Url;
char *Dir;
char c;
Url = *UrlPtr;
Dir = *DirPtr;
// TODO: special treatment for host part for ':'
for (;;)
{
if (len <= 0)
dreturn (D_CACHE, 0); /* perhaps TODO: break long url parts into multiple parts . */
c = *Url++;
if (! InvalidChars [c])
{
if (PartNumber == 1) /* host name is case insensitive */
*Dir++ = tolower (c);
else
*Dir++ = c;
len--;
}
else if (c == '/') /* reached part end */
{
if (Dir == *DirPtr) /* empty directory name? */
{
*Dir++ = '@';
*Dir++ = '!';
}
*Dir = '\0';
*DirPtr = Dir;
*UrlPtr = Url;
dreturn (D_CACHE, 3);
}
else if (c == ':' && PartNumber == 0) /* special treatment: protocoll part */
{
if (Url [0] == '/' && Url [1] == '/')
{
*Dir = '\0';
*DirPtr = Dir;
*UrlPtr = Url + 2; /* skip :// part */
dreturn (D_CACHE, 3);
}
dreturn (D_CACHE, 0); /* no standard protocoll part - skip it */
}
else if (c == '\0') /* reached file end */
{
*Dir = '\0';
*DirPtr = Dir;
*UrlPtr = Url;
dreturn (D_CACHE, 1);
}
else /* escape special character */
{
*Dir++ = '!';
*Dir++ = InvalidChars [c];
assert (! InvalidChars [InvalidChars [c]]);
len -=2;
}
}
}
/*)) */
/*(( "HashPartial ()" */
/* private: Hash partial file name.
* returns: 0: not possible, 2: final filename part reached 4: intermediate dir part */
/* Url and Dir pointers are updated accordingly (only on return value != 0). */
/* The first two parts may have special treatment (protocol and host) */
static int HashPartial (const char **UrlPtr, char **DirPtr, const char *FullUrl, int PartNumber)
{
const char *Url, *Last;
int Hash = 0;
char __aligned Bytes [4] = { 0, 0, 0, 0 };
#if (sizeof(int) != 4)
# error Only 4 byte ints supported!
#endif
Url = *UrlPtr;
if (! (Last = strchr (Url, '/')) ) /* check end of partial url */
Last = Url + strlen (Url);
/* Hash values are always computed over the full URL up to its partial end. */
for (Url = FullUrl; Url < Last; Url += 4)
{
Hash = (Hash << 4) ^ (Hash >> 28);
strncpy (Bytes, Url, 4); /* Attention! There may be bytes remaining from the last action in the array */
Hash ^= * (int *) Bytes; /* But as their values are deterministic we can use them... */
debug (D_HASH, ("0x%08x - 0x%08x (%c%c%c%c)\n", * (int *) Bytes, Hash, Bytes[0], Bytes[1], Bytes[2], Bytes[3]));
}
#if (MAX_FILE_LEN < 12)
# error Only filelenghts >= 12 is supported right now
#endif
debug (D_HASH, ("-> 0x%08x\n", Hash));
sprintf (*DirPtr, "@!%08x", Hash);
*UrlPtr = Last + 1;
*DirPtr += 10;
if (*Last == '/')
dreturn (D_CACHE, 4);
dreturn (D_CACHE, 2);
}
/*)) */
/*(( "HashRemaining ()" */
/* private: Hash remaining url name.
* returns: 0: not possible, 2: final filname part reached */
/* Url and Dir pointers are updated accordingly (only on return value != 0). */
static int HashRemaining (const char **UrlPtr, char **DirPtr, const char *FullUrl)
{
const char *Url, *Last;
int Hash = 0;
char __aligned Bytes [4] = { 0, 0, 0, 0 };
#if (sizeof(int) != 4)
# error Only 4 byte ints supported!
#endif
Last = *UrlPtr + strlen (*UrlPtr);
/* Hash values are always computed over the full URL. */
for (Url = FullUrl; Url < Last; Url += 4)
{
Hash = (Hash << 4) ^ (Hash >> 28);
strncpy (Bytes, Url, 4); /* Attention! There may be bytes remaining from the last action in the array */
Hash ^= * (int *) Bytes; /* But as their values are deterministic we can use them... */
debug (D_HASH, ("0x%08x - 0x%08x (%c%c%c%c)\n", * (int *) Bytes, Hash, Bytes[0], Bytes[1], Bytes[2], Bytes[3]));
}
#if (MAX_FILE_LEN < 12)
# error Only filelenghts >= 12 is supported right now
#endif
debug (D_HASH, ("=> 0x%08x\n", Hash));
sprintf (*DirPtr, "@!%08x", Hash);
*UrlPtr = Last + 1;
*DirPtr += 10;
dreturn (D_CACHE, 2);
}
/*)) */
/*(( "ReadFile ()" */
/* Read file contents into static (!) buffer. Maximum length: MAX_URLBUFFER. String is always 0-terminated.
* Returns NULL on error. */
static char *ReadFile (const char *name)
{
static char Buffer [MAX_URLBUFFER];
BPTR file;
long len;
Buffer [0] = '\0';
if (! (file = Open ((char *) name, MODE_OLDFILE)))
return NULL;
if ( (len = Read (file, Buffer, MAX_URLBUFFER-1)) <= 0)
{
Close (file);
return NULL;
}
Close (file);
Buffer [len] = '\0';
return Buffer;
}
/*)) */
/*(( "DeleteFiles ()" */
/* Delete all files inside a directory. */
/* Returns 0 on *major* failure. */
int DeleteFiles (const char *Dir)
{
BPTR lock, olddir;
struct ExAllData *E;
struct ExAllControl *ExAllCtrl;
char Buffer [512];
int More;
debug (D_FILES, ("scanning '%s'\n", Dir));
if (! (lock = Lock ((char *) Dir, ACCESS_READ)))
dreturn (D_FILES, 0);
if (! (ExAllCtrl = (struct ExAllControl *) AllocDosObject(DOS_EXALLCONTROL,NULL)))
{
PrintFault (IoErr (), "can't alloc dosobject");
UnLock (lock);
dreturn (D_FILES, 1);
}
olddir = CurrentDir (lock);
do
{
More = ExAll (lock, (struct ExAllData *) Buffer, sizeof (Buffer), ED_NAME, ExAllCtrl);
if (! More && IoErr () != ERROR_NO_MORE_ENTRIES)
{
PrintFault (IoErr (), "ExAll() Error");
break;
}
if (! ExAllCtrl->eac_Entries)
continue;
E = (struct ExAllData *) Buffer;
while (E)
{
debug (D_FILES, ("deleting '%s'\n", E->ed_Name));
if (! DeleteFile (E->ed_Name))
LogErr (NULL, L_ERROR, NULL, -1, "on deleting temporary file '%s'", E->ed_Name);
else
LogErr (NULL, L_INFO, NULL, 0, "deleting old temporary file '%s'", E->ed_Name);
E = E->ed_Next;
}
} while (More);
CurrentDir (olddir);
FreeDosObject (DOS_EXALLCONTROL, ExAllCtrl);
UnLock (lock);
dreturn (D_FILES, 1);
}
/*)) */
/*(( "CacheInit () / CacheExit ()" */
/* Initialize cache. Initialize invalid char table. Delete all files in @temp directory. */
int CacheInit (void)
{
BPTR lock;
int i, e;
/* Test existance of CACHEDIRVALIDFILE and @trash directory */
lock = Lock (CACHEDIRVALIDFILE, ACCESS_READ);
if (! lock)
{
PrintFault (IoErr (), "can't lock '" CACHEDIRVALIDFILE "' - seems to be the wrong directory");
return 0;
}
UnLock (lock);
if (! (lock = Lock ("@trash", ACCESS_READ)))
{
PrintFault (IoErr (), "can't lock '@trash' dir");
return 0;
}
UnLock (lock);
/* Initialize invalid char table. Only the first pass may needs adaption for more invalid chars. */
/* invalid chars: control characters, 127, 255, 32-34(' !"'), 160(' '), '@', '\0', ':', '/' */
/* Perhaps we should disallow the following to (according to the DOS manual - but nevertheless,
* they work well, so we don't do anything about them...
* *not* escaped: ';', '*', '?', '`', '#', '%' */
/* first pass: mark invalid chars */
for (i = 0; i <= 34; i++) /* control characters, 32-34, 0 */
InvalidChars [i] = 1;
for (i = 127; i <= 160; i++) /* control characters 2., 127, 160 */
InvalidChars [i] = 1;
InvalidChars [255] = InvalidChars ['@'] = InvalidChars [':'] = InvalidChars ['/'] = 1;
/* second pass: set marked chars (e is current escape character) */
for (e = 0; e < 256; e++)
if (! InvalidChars [e])
break;
for (i = 0; i < 256; i++)
if (InvalidChars [i])
{
assert (e < 256);
debug (D_HASH, ("Escaping char 0x%02x by '%c'\n", i, e));
EscapedChars [e] = i;
InvalidChars [i] = e;
do
e++;
while (e < 256 && (InvalidChars [e] || EscapedChars [tolower (e)] || EscapedChars [toupper (e)]));
}
/* Delete all files in @temp and @trash */
if (! DeleteFiles ("@temp"))
{
PrintFault (IoErr (), "error while cleaning '@temp' dir");
return 0;
}
if (! DeleteFiles ("@trash"))
{
PrintFault (IoErr (), "error while cleaning '@trash' dir");
return 0;
}
return 1;
}
void CacheExit (void)
{
}
/*)) */
/*(( "CacheGet ()" */
/* the *major* one: check cache url, construct cache filename, check ambiguity */
int CacheGet (cachefile_t *Cache, const char *Url, request_t *Req)
{
char *Dir;
const char *UrlDone, *UrlThis;
char *DirDone, *DirThis;
char *Check;
BPTR lock;
BPTR file;
int retval, PartNumber;
static int TempNumber = 0;
__aligned struct FileInfoBlock Fib; /* too lazy to use AllocDosObject() and do cleanups... */
assert (Cache);
assert (Url);
assert (Cache->File == NULL);
Cache->Req = Req;
Dir = Cache->FileName;
UrlDone = Url;
DirDone = Dir;
*DirDone = '\0';
PartNumber = 0;
TempNumber++;
for (;;)
{
UrlThis = UrlDone;
DirThis = DirDone;
if (DirDone - Dir > MAX_PATH_LEN - MAX_FILE_LEN - 3 ||
PartNumber >= MAX_FILE_DEPTH-1) /* Url is too long -> Hash remaining */
{
if (! (retval = HashRemaining (&UrlDone, &DirDone, Url)) )
dreturn (D_CACHE, -1);
}
else if (! (retval = EscapePartial (&UrlDone, &DirDone, PartNumber)) ) /* try escaping forbidden characters */
{
if (PartNumber < 1) /* on escaping 1st or 2nd part: no special parts anymore! */
PartNumber = 1;
if (! (retval = HashPartial (&UrlDone, &DirDone, Url, PartNumber)) ) /* failed -> hash partial */
if (! (retval = HashRemaining (&UrlDone, &DirDone, Url)) ) /* failed -> hash remaining */
dreturn (D_CACHE, -1);
}
switch (retval) {
case 1: /**** filename part (last part) was reached ****/
*DirDone++ = '@';
*DirDone = '\0';
if (! (lock = Lock (Dir, ACCESS_READ)) )
dreturn (D_CACHE, 0); /* no file so far */
if (! Examine (lock, &Fib))
{
LogErr (Cache->Req, L_ERROR, NULL, -1, "on examing '%s'", Dir);
UnLock (lock);
dreturn (D_CACHE, -1);
}
UnLock (lock);
if (strcmp (DirThis, Fib.fib_FileName) == 0) /* ambiguity? (it is sufficient here to check the filename only) */
{
#if (MAX_TEMP_LEN < 17)
# error Only temp path lengths >= 17 supported
#endif
sprintf (Cache->TempName, "@temp/rq%08x", TempNumber++); /* new file */
dreturn (D_CACHE, 1);
}
UrlDone = UrlThis;
DirDone = DirThis;
if (! (retval = HashRemaining (&UrlDone, &DirDone, Url)) ) /* failed -> hash remaining */
dreturn (D_CACHE, -1);
/* no break! */ /* new name -> have to make another ambiguity check! */
case 2: /**** filename part (last part) as hash ****/
*DirDone++ = '@';
*DirDone = '\0';
DirThis [1] = '@'; /* check URL file */
if ( (Check = ReadFile (Dir)) )
{
DirThis [1] = '!';
if (strcmp (Check, Url) == 0)
{
if (! (lock = Lock (Dir, ACCESS_READ)) )
dreturn (D_CACHE, 0); /* no file so far ?!? */
UnLock (lock);
sprintf (Cache->TempName, "@temp/@!%08x", TempNumber++); /* new file */
dreturn (D_CACHE, 1);
}
else
dreturn (D_CACHE, -1);
}
DirThis [1] = '!';
dreturn (D_CACHE, 0);
case 3: /**** partial directory name ****/
if (! (lock = Lock (Dir, ACCESS_READ)) ) /* check availability / ambiguity */
{ /* not yet there -> create (no ambiguity check needed) */
if (! (lock = CreateDir (Dir)) )
{
LogErr (Cache->Req, L_ERROR, NULL, -1, "on creating dir '%s'", Dir);
dreturn (D_CACHE, -1);
}
UnLock (lock);
strcpy (DirDone, "/@dirurl"); /* create directory url filename */
if (! (file = Open (Dir, MODE_NEWFILE)))
{
LogErr (Cache->Req, L_ERROR, NULL, -1, "on creating dirfile '%s'", Dir);
*DirDone = '\0';
DeleteFile (Dir);
dreturn (D_CACHE, -1);
}
Write (file, (char *) Url, UrlDone - Url);
if (! Close (file))
LogErr (Cache->Req, L_ERROR, NULL, -1, "writing to dirfile in '%s' - may be inconsistent", Dir);
*++DirDone = '\0'; /* '/' was already added by strcpy... ;) */
break;
}
UnLock (lock);
strcpy (DirDone, "/@dirurl"); /* create directory url filename */
if (! (Check = ReadFile (Dir)))
{
LogErr (NULL, L_ERROR, NULL, -1, "on reading file '%s'", Dir);
dreturn (D_CACHE, -1);
}
*++DirDone = '\0'; /* '/' was already added by strcpy... ;) */
if (strncmp (Url, Check, strlen (Check)) == 0) /* ambiguity? */
break;
UrlDone = UrlThis;
DirDone = DirThis;
if (! (retval = HashPartial (&UrlDone, &DirDone, Url, PartNumber)) ) /* failed -> hash dir name */
dreturn (D_CACHE, -1);
/* no break! */ /* new name -> have to make another ambiguity check! */
case 4: /**** partial directory name ****/
DirThis [1] = '@'; /* check URL file */
if ( (Check = ReadFile (Dir)) )
{
DirThis [1] = '!'; /* Url file there -> check ambiguity */
if (strncmp (Check, Url, strlen (Check)) == 0)
{
if (! (lock = Lock (Dir, ACCESS_READ)) ) /* should be already there, but check it anyway */
{
LogErr (Cache->Req, L_INFO, NULL, -1, "dir '%s' was lost", Dir);
DirThis [1] = '@';
DeleteFile (Dir); /* Try to clean up */
dreturn (D_CACHE, -1);
}
UnLock (lock);
*DirDone++ = '/';
*DirDone = '\0';
break;
}
else
dreturn (D_CACHE, -1);
}
if (! (file = Open (Dir, MODE_NEWFILE)) ) /* no URL file -> create new one */
{
LogErr (Cache->Req, L_ERROR, NULL, -1, "on creating hash urlfile '%s'", Dir);
dreturn (D_CACHE, -1);
}
Write (file, (char *) Url, UrlDone - Url);
if (! Close (file))
{
LogErr (Cache->Req, L_ERROR, NULL, -1, "on creating hash urlfile '%s'", Dir);
dreturn (D_CACHE, -1);
}
DirThis [1] = '!';
if (! (lock = CreateDir (Dir)) )
{
LogErr (Cache->Req, L_ERROR, NULL, -1, "on creating dir '%s'", Dir);
DirThis [1] = '@';
DeleteFile (Dir); /* try to clean up */
dreturn (D_CACHE, -1);
}
UnLock (lock);
strcpy (DirDone, "/@dirurl"); /* create directory url filename */
if (! (file = Open (Dir, MODE_NEWFILE)))
{
LogErr (Cache->Req, L_ERROR, NULL, -1, "on creating dirfile '%s'", Dir);
dreturn (D_CACHE, -1);
}
Write (file, (char *) Url, UrlDone - Url);
if (! Close (file))
LogErr (Cache->Req, L_ERROR, NULL, -1, "writing to dirfile in '%s' - may be inconsistent", Dir);
*++DirDone = '\0'; /* '/' was already added by strcpy... ;) */
break;
default:
assert (0);
break;
}
PartNumber++;
}
/* NOTREACHED */
}
/*)) */
/*(( "CacheOpenOld ()" */
/* Open existing cache file. */
int CacheOpenOld (cachefile_t *Cache)
{
assert (Cache->File == NULL);
Cache->TempName [0] = '\0';
debug (D_FILES, ("open old cache '%s'\n", Cache->File));
if (! (Cache->File = Open (Cache->FileName, MODE_OLDFILE)))
{
LogErr (Cache->Req, L_ERROR, NULL, -1, "on opening old cache file '%s'", Cache->FileName);
return -1;
}
return 0;
}
/*)) */
/*(( "CacheOpenNew ()" */
/* Open new cache file. */
int CacheOpenNew (cachefile_t *Cache, const char *Url)
{
char *name, *Part;
BPTR file;
assert (Cache->File == NULL);
name = Cache->TempName [0] ? Cache->TempName : Cache->FileName;
debug (D_FILES, ("open new cache '%s', final name '%s'\n", name, Cache->FileName));
if (! (Cache->File = Open (name, MODE_NEWFILE)))
{
LogErr (Cache->Req, L_ERROR, NULL, -1, "on opening new cache file '%s'", name);
return -1;
}
if (! ChangeMode (CHANGE_FH, Cache->File, MODE_READWRITE))
LogErr (Cache->Req, L_WARN, NULL, -1, "ChangeMode() failed for file '%s'", name);
/* check for hashed file */
if ( (Part = strrchr (name, '/')) )
Part++;
else
Part = name;
if (Part [0] == '@' && Part [1] == '!')
{
assert (Part [2] != '\0'); /* should *not* be a (empty name) directory... */
Part [1] = '@'; /* Create (perhaps temporary) Url file */
if (! (file = Open (name, MODE_NEWFILE)) )
LogErr (Cache->Req, L_ERROR, NULL, -1, "on creating temporary hash urlfile '%s'", name);
else
{
Write (file, (char *) Url, (long) strlen (Url));
if (! Close (file))
LogErr (Cache->Req, L_ERROR, NULL, -1, "on creating temporary hash urlfile '%s'", name);
}
Part [1] = '!';
}
return 0;
}
/*)) */
/*(( "CacheClose ()" */
/* Close cache file, move files, tidy up. */
void CacheClose (cachefile_t *Cache, int Ok)
{
static short TrashNumber = 0; /* needed for trash files (accessed files to be removed)... */
debug (D_FILES, ("closing cache file '%s', temp name '%s', ok:%s\n", Cache->FileName, Cache->TempName, Ok ? "yes" : "no"));
if (Cache->File)
{
BPTR lock;
char *Part, *PTmp;
char *name = Cache->TempName [0] ? Cache->TempName : Cache->FileName;
char TrashName [16];
if ( (PTmp = strrchr (name, '/')) )
PTmp++;
else
PTmp = name;
if (Seek (Cache->File, 0, OFFSET_CURRENT) == 0) /* Delete empty files */
{
if (Ok)
LogErr (Cache->Req, L_INFO, NULL, 0, "removing empty cache file");
Ok = 0;
}
if (! Close (Cache->File))
LogErr (Cache->Req, L_ERROR, NULL, -1, "on closing cache file '%s'", name);
else
{
if (Ok && Cache->TempName [0])
{
if ( (Part = strrchr (Cache->FileName, '/')) ) /* PTmp is used on TempName */
Part++;
else
Part = Cache->FileName;
if (Part [0] == '@' && Part [1] == '!') /* hashed file (the *real* name is tested!) */
{
debug (D_FILES, ("creating hash url file\n"));
assert (Part [2] != '\0');
Part [1] = PTmp [1] = '@'; /* check URL file */
if ( (lock = Lock (Cache->FileName, ACCESS_READ)) )
{
UnLock (lock);
if (! DeleteFile (Cache->FileName)) /* remove old url file (may be ambigous) */
{
sprintf (TrashName, "@trash/o%04x", TrashNumber++); /* the file is open from another connection */
if (! Rename (Cache->FileName, TrashName)) /* so we move it to the trash directory (httpdelete will kill it...) */
LogErr (Cache->Req, L_ERROR, NULL, -1, "on trashing hash url file '%s'", Cache->FileName);
}
}
if (! Rename (Cache->TempName, Cache->FileName))
{
LogErr (Cache->Req, L_ERROR, NULL, -1, "on renaming hash url file '%s'", name);
Ok = 0;
}
Part [1] = PTmp [1] = '!';
}
if (Ok)
{
if ( (lock = Lock (Cache->FileName, ACCESS_READ)) )
{
UnLock (lock);
if (! DeleteFile (Cache->FileName)) /* remove old cache file */
{
sprintf (TrashName, "@trash/o%04x", TrashNumber++); /* the file is open from another connection */
if (! Rename (Cache->FileName, TrashName)) /* so we move it to the trash directory (httpdelete will kill it...) */
LogErr (Cache->Req, L_ERROR, NULL, -1, "on trashing cache file '%s'", Cache->FileName);
}
}
if (! Rename (name, Cache->FileName))
LogErr (Cache->Req, L_ERROR, NULL, -1, "on renaming cache file '%s'", name);
/* name = Cache->FileName; */ /* not needed... */
}
}
}
if (! Ok)
{
debug (D_FILES, ("deleting cache file '%s'\n", name));
if (! DeleteFile (name)) /* remove old cache file */
{
sprintf (TrashName, "@trash/o%04x", TrashNumber++); /* the file is open from another connection */
if (! Rename (name, TrashName)) /* so we move it to the trash directory (httpdelete will kill it...) */
LogErr (Cache->Req, L_ERROR, NULL, -1, "on trashing cache file '%s'", name);
}
if (PTmp [0] == '@' && PTmp [1] == '!')
{
debug (D_FILES, ("deleting cache url file\n"));
assert (PTmp [2] != '\0');
PTmp [1] = '@';
if (! DeleteFile (name)) /* remove old hash urlfile */
{
sprintf (TrashName, "@trash/o%04x", TrashNumber++); /* the file is open from another connection */
Rename (name, TrashName);
}
/* PTmp [1] = '!'; */ /* not needed... */
}
}
Cache->File = NULL;
}
Cache->TempName [0] = '\0';
Cache->Req = NULL; /* you never know... */
}
/*)) */
/*(( "CacheRead () / CacheWrite ()" */
/* read something from cache file */
int CacheRead (cachefile_t *Cache, void *Buf, int Len)
{
if (Cache->File != NULL)
return (Read (Cache->File, Buf, (long) Len));
return 0;
}
/* write something to cache file */
int CacheWrite (cachefile_t *Cache, const void *Buf, int Len)
{
if (Cache->File != NULL)
return (Write (Cache->File, (void *) Buf, (long) Len));
return Len;
}
/*)) */
/*(( "CacheResolve ()" */
/* get url name from cache file */
int CacheResolve (const char *File, char *Url)
{
char Dir [MAX_PATH_LEN];
const char *c;
char *cp;
strcpy (Dir, File);
if ( (cp = strrchr (Dir, '/')) )
cp++;
else
cp = Dir;
strcpy (cp, "@dirurl");
if (! (c = ReadFile (Dir)) && cp != Dir) /* ReadFile may return NULL on empty root @dirurl */
dreturn (D_CACHE, 0);
*cp = '\0';
strcpy (Url, c);
cp = Url + strlen (Url);
if ( (c = strrchr (File, '/')))
c++;
else
c = File;
switch (*c) {
case 0:
dreturn (D_CACHE, 0); /* 'file' was a directory */
case '@':
switch (*++c) {
case '!':
if (c [1] == '\0') /* empty directory file */
dreturn (D_CACHE, 0); /* should only occure as directory */
strcpy (Dir, File);
Dir [c - File] = '@';
if (! (c = ReadFile (Dir)) )
dreturn (D_CACHE, 0);
strcpy (Url, c);
dreturn (D_CACHE, 1);
case '@': /* this is a hash url file */
dreturn (D_CACHE, 0);
case 0:
*cp = '\0'; /* empty filename: Urls http://abc.cde/xxxx/yyyy/ <- */
dreturn (D_CACHE, 1);
default:
dreturn (D_CACHE, 0); /* special files */
}
default:
for (;;)
switch ( (*cp++ = *c++) ) {
case '@':
if (*c != '\0')
dreturn (D_CACHE, 0);
cp [-1] = '\0';
dreturn (D_CACHE, 1);
case '!':
cp [-1] = EscapedChars [c[-1]];
assert (InvalidChars [EscapedChars [c[-1]]]); /* only invalid chars *have* to be escaped! */
break;
case 0:
dreturn (D_CACHE, 0); /* file was a directory */
/* default: continue */
}
}
}
/*)) */
/*(( "CacheRemove ()" */
/* Delete cache file */
int CacheRemove (const char *File, int DoDelete)
{
char Related [MAX_PATH_LEN];
const char *Part;
BPTR lock;
if ( (Part = strrchr (File, '/')) ) /* begin of filename part */
Part++;
else
Part = File;
if (strncmp (File, "@trash/", 7) == 0) /* files in the trash directory are always allowed to be deleted */
{
if (DoDelete)
if (! DeleteFile ((char *) File))
{
if (IoErr () != 205)
return 0;
return 4; /* object not found */
}
return 1;
}
if (Part [0] == '@')
{
if (Part [1] != '!')
{
if (strcmp (Part, "@dirurl") == 0) /* directory special file */
return 2;
if (Part [1] == '@') /* url related file */
{
strcpy (Related, File);
Related [Part - File + 1] = '!'; /* related hash file */
if ( (lock = Lock (Related, ACCESS_READ)))
{
UnLock (lock);
return 5;
}
if (! DoDelete) /* hashed file is lost... */
return 7;
}
else if (Part [1] != '\0') /* no empty name file */
return 6;
}
else
{
strcpy (Related, File);
Related [Part - File + 1] = '@'; /* related url file */
if (! (lock = Lock (Related, ACCESS_READ)))
if (! DoDelete)
return 7; /* url file is lost... */
UnLock (lock);
}
}
if (! DoDelete)
return 1;
/* TODO: when a file cannot be deleted it should be renamed into a trash directory */
if (Part [0] == '@' && Part [1] == '!') /* hashed file */
{
strcpy (Related, File);
Related [Part - File + 1] = '@'; /* url name file */
if (! DeleteFile (Related))
{
if (IoErr () != 205) /* don't worry when object not found */
return 0;
}
}
if (! DeleteFile ((char *) File))
{
if (IoErr () != 205)
return 0;
return 4; /* object not found */
}
return 1;
}
/*)) */
/*(( "CacheRemoveDir ()" */
/* Delete cache dir */
int CacheRemoveDir (const char *Dir, int DoDelete)
{
char File [MAX_PATH_LEN];
char *Part;
const char *Check;
/* check whether it was a hashed directory */
if ( (Check = strrchr (Dir, '/')) ) /* begin of filename part */
Check++;
else
Check = Dir;
if (Check [0] == '@' && Check [1] != '!')
{
if (strncmp (Dir, "@trash/", 7) == 0)
{
if (! DoDelete) /* scan trash dir always */
return 1;
return 2; /* but do never ever delete it */
}
return 2;
}
if (! DoDelete)
return 1;
strcpy (File, Dir);
Part = File + strlen (File);
strcpy (Part, "/@dirurl");
if (! DeleteFile (File))
{
if (IoErr () != 205) /* if object not found, don't worry */
return 0;
}
*Part = '\0';
if (! DeleteFile ((char *) Dir))
return 0;
if (Check [0] == '@' && Check [1] == '!')
{
File [Check - Dir + 1] = '@'; /* File contains a copy of Dir */
if (! DeleteFile ((char *) File)) /* delete related file */
return 0;
}
return 1;
}
/*)) */